package com.yitiao.socket.chatroom.nio;

import com.yitiao.socket.chatroom.CommonConst;
import com.yitiao.socket.chatroom.MyClient;
import lombok.SneakyThrows;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Set;

public class NioChatClient extends MyClient {

    public NioChatClient(SocketChannel client) {
        this.nioClient = client;
    }

    @SneakyThrows
    public void start() {
//        new Thread(new ClientInputHandler(this)).start();
        nioClient.configureBlocking(false);
        this.selector = Selector.open();
        nioClient.register(selector, SelectionKey.OP_CONNECT);
        nioClient.connect(new InetSocketAddress(CommonConst.HOST, CommonConst.PORT));

        while (true) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey key : selectionKeys) {
                selectorHandler(key);
            }
            selectionKeys.clear();
        }
    }

    private void selectorHandler(SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        if (key.isConnectable()){
            if (client.isConnectionPending()) {
                client.finishConnect();
                // 处理用户的输入
                new Thread(new NioClientInputHandler(this)).start();
            }
            client.register(selector, SelectionKey.OP_READ);
        }
        // READ事件 -  服务器转发消息
        else if (key.isReadable()) {
            String msg = receive(client);
            if (msg.isEmpty()) {
                // 服务器异常
                selector.close();
            } else {
                System.out.println(msg);
            }
        }
    }

    @SneakyThrows
    private String receive(SocketChannel client) {
        rBuffer.clear();
        while (client.read(rBuffer) > 0);
        rBuffer.flip();
        return String.valueOf(charset.decode(rBuffer));
    }

    @SneakyThrows
    public void send(String msg) {
        if (!msg.isEmpty()) {
            wBuffer.clear();
            wBuffer.put(charset.encode(msg));
            wBuffer.flip();
            while (wBuffer.hasRemaining()) {
                nioClient.write(wBuffer);
            }

            // 检查用户是否准备退出
            if (msg.equals(CommonConst.QUIT)) {
                selector.close();
            }
        }

    }

    @SneakyThrows
    public void close() {
        this.isQuit = true;
        client.close();
    }

    @SneakyThrows
    public static void main(String[] args) {
        SocketChannel socketChannel = SocketChannel.open();
        NioChatClient client = new NioChatClient(socketChannel);
        client.start();
    }
}
